package org.jing.ext.spring.component;

import org.jing.core.lang.JingException;
import org.jing.core.logger.JingLogger;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.Semaphore;

/**
 * Description: Socket分发底层类 <br>
 * 继承的子类需要标注@Component注解交给springboot做管理, 必要时使用组件名区分组件 <br>
 *
 * @author bks <br>
 * @see org.jing.ext.spring.component.ExampleSocketDispatcher
 * @since 2023-01-28 <br>
 */
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Deprecated
public abstract class BaseSocketDispatcher extends Thread {
    private static final JingLogger LOGGER = JingLogger.getLogger(BaseSocketDispatcher.class);

    protected String clientName = getClientName();

    protected int hashCode = hashCode();

    protected String ip;

    protected int port;

    protected Socket socket;

    protected Semaphore semaphore;

    public abstract String getClientName();

    public void init(Socket sock, Semaphore semaphore) {
        this.socket = sock;
        this.semaphore = semaphore;
        this.ip = socket.getInetAddress().getHostAddress();
        this.port = socket.getPort();
    }

    protected void finalize() throws Throwable {
        super.finalize();
        if (null != socket && !socket.isClosed()) {
            try {
                socket.close();
            }
            catch (JingException e) {
                throw e;
            }
            catch (Throwable t) {
                LOGGER.error(t);
            }
        }
    }

    @Override public void run() {
        try {
            if (condition()) {
                semaphore.acquire();
                LOGGER.imp("[{}: {}] start. [ip: {}][port: {}][availablePermits: {}]", clientName, hashCode, ip, port, semaphore.availablePermits());
                InputStream reader = socket.getInputStream();
                OutputStream writer = socket.getOutputStream();
                this.operation(reader, writer);
            }
        }
        catch (JingException e) {
            throw e;
        }
        catch (Throwable t) {
            LOGGER.error("failed to run client: {}", hashCode());
            LOGGER.error(t);
            fail(t);
        }
        finally {
            release();
        }
    }

    protected abstract void operation(InputStream inputStream, OutputStream outputStream) throws Throwable;

    private void release() {
        beforeRelease();
        this.semaphore.release();
        if (null != socket && !socket.isClosed()) {
            try {
                socket.close();
                LOGGER.imp("[{}: {}] release...", getClientName(), hashCode());
            }
        catch (JingException e) {
            throw e;
        }
        catch (Throwable t) {
                LOGGER.error(t);
            }
        }
        afterRelease();
    }

    protected boolean condition() {
        return true;
    }

    protected void fail(Throwable t) {}

    protected void beforeRelease() {}

    protected void afterRelease() {}
}
